package stringutils

import (
	"bytes"
	"compress/zlib"
	"container/list"
	"fmt"
	"gitee.com/ichub/webcli/common/base/basemodel"
	"gitee.com/ichub/webcli/common/base/baseutils"
	"github.com/sirupsen/logrus"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"reflect"
	"strconv"
	"strings"
	"text/template"
	"time"
	"unicode"
)

func Any2Str(v interface{}) string {
	return ToStringWith(v)
}
func ToStringWith(in interface{}) (str string) {

	switch value := in.(type) {
	case int:
		str = strconv.Itoa(value)
	case int8:
		str = strconv.Itoa(int(value))
	case int16:
		str = strconv.Itoa(int(value))
	case int32: // same as `rune`
		str = strconv.Itoa(int(value))
	case int64:
		str = strconv.FormatInt(value, 10)
	case uint:
		str = strconv.FormatUint(uint64(value), 10)
	case uint8:
		str = strconv.FormatUint(uint64(value), 10)
	case uint16:
		str = strconv.FormatUint(uint64(value), 10)
	case uint32:
		str = strconv.FormatUint(uint64(value), 10)
	case uint64:
		str = strconv.FormatUint(value, 10)
	case float32:
		str = strconv.FormatFloat(float64(value), 'f', -1, 32)
	case float64:
		str = strconv.FormatFloat(value, 'f', -1, 64)
	case bool:
		str = strconv.FormatBool(value)
	case string:
		str = value
	case *string:
		str = *value
	case []byte:
		str = string(value)
	case time.Duration:
		str = strconv.FormatInt(int64(value), 10)
	case fmt.Stringer:
		str = value.String()
	case error:
		str = value.Error()

	}
	return str
}
func ZipStr(origin string) (content string) {
	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write([]byte(origin))
	w.Close()
	return b.String()
}

func UnzipStr(zipContent string) (originInfo []byte) {
	var b bytes.Buffer
	b.WriteString(zipContent)
	r, err := zlib.NewReader(&b)
	if err != nil {
		fmt.Println(" err : ", err)
	}
	defer r.Close()
	originInfo, err = ioutil.ReadAll(r)
	if err != nil {
		fmt.Println(" err : ", err)
	}

	return originInfo
}

func Capitalize(str string) string {
	var upperStr string
	vv := []rune(str) // 后文有介绍
	for i := 0; i < len(vv); i++ {
		if i == 0 {
			if vv[i] >= 97 && vv[i] <= 122 { // 后文有介绍
				vv[i] -= 32 // string的码表相差32位
				upperStr += string(vv[i])
			} else {
				fmt.Println("Not begins with lowercase letter,")
				return str
			}
		} else {
			upperStr += string(vv[i])
		}
	}
	return upperStr
}
func Camel2Case(name string) string {
	buffer := NewBuffer()
	for i, r := range name {
		if unicode.IsUpper(r) {
			if i != 0 {
				buffer.Append('_')
			}
			buffer.Append(unicode.ToLower(r))
		} else {
			buffer.Append(r)
		}
	}
	return buffer.String()
}

func UcfirstCase2Camel(str string) string {
	s := Case2Camel(str)
	return Ucfirst(s)
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

// 首字母大写
func Ucfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

// 首字母小写
func Lcfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToLower(v)) + str[i+1:]
	}
	return ""
}

func RandomString(n int) string {
	var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	result := make([]byte, n)
	rand.Seed(time.Now().Unix())
	for i := range result {
		result[i] = letters[rand.Intn(len(letters))]
	}
	return string(result)
}

// 内嵌bytes.Buffer，支持连写
type Buffer struct {
	*bytes.Buffer
}

func NewBuffer() *Buffer {
	return &Buffer{Buffer: new(bytes.Buffer)}
}

func (b *Buffer) Append(i interface{}) *Buffer {
	switch val := i.(type) {
	case int:
		b.append(strconv.Itoa(val))
	case int64:
		b.append(strconv.FormatInt(val, 10))
	case uint:
		b.append(strconv.FormatUint(uint64(val), 10))
	case uint64:
		b.append(strconv.FormatUint(val, 10))
	case string:
		b.append(val)
	case []byte:
		b.Write(val)
	case rune:
		b.WriteRune(val)
	}
	return b
}

func (b *Buffer) append(s string) *Buffer {
	defer func() {
		if err := recover(); err != nil {
			log.Println("*****内存不够了！******")
		}
	}()
	b.WriteString(s)
	return b
}

func List2stringBy(lst *list.List, sep string) string {
	var rr []string
	rr = append(rr, sep)
	for i := lst.Front(); i != nil; i = i.Next() {
		rr = append(rr, i.Value.(string))
	}
	return strings.Join(rr, sep)
}

func List2string(lst *list.List) string {
	return List2stringBy(lst, "\n")
}

func parseTemplate(t *template.Template, vars interface{}) string {
	var tmplBytes bytes.Buffer

	err := t.Execute(&tmplBytes, vars)
	if err != nil {
		panic(err)
	}
	return tmplBytes.String()
}

func ParseTemplateString(str string, vars interface{}) string {
	tmpl, err := template.New("tmpl").Parse(str)

	if err != nil {
		panic(err)
	}
	return parseTemplate(tmpl, vars)
}

func PrintList(lst *list.List) {
	fmt.Println("\n")
	for i := lst.Front(); i != nil; i = i.Next() {
		fmt.Println(i.Value)
	}
}
func LogList(lst *list.List) {
	log.Println("\n")
	for i := lst.Front(); i != nil; i = i.Next() {
		log.Println(i.Value)
	}
}

type UnixTime time.Time

func (t UnixTime) MarshalJSON() ([]byte, error) {
	stamp := ""

	return []byte(stamp), nil
}
func NameOfType(v interface{}) string {
	var modelName = reflect.TypeOf(v)
	var mName = strings.ReplaceAll(modelName.String(), "\\*", "")
	mName = strings.ReplaceAll(modelName.String(), ".", "")

	mName = strings.TrimPrefix(mName, "*")
	logrus.Info("NameOfType=", mName)
	return Camel2Case(mName)
}
func Inttime2Str(timestamp int64) string {
	//日期转化为时间戳
	timeLayout := "2006-01-02 15:04:05" //转化所需模板
	datetime := time.Unix(timestamp, 0).Format(timeLayout)
	return datetime

}
func Strtime2Time(datetime string) time.Time {
	//日期转化为时间戳
	timeLayout := "2006-01-02 15:04:05"  //转化所需模板
	loc, _ := time.LoadLocation("Local") //获取时区
	tmp, _ := time.ParseInLocation(timeLayout, datetime, loc)
	return tmp
}

func Strtime2Int(datetime string) (timestamp int64) {
	//日期转化为时间戳
	timeLayout := "2006-01-02 15:04:05"  //转化所需模板
	loc, _ := time.LoadLocation("Local") //获取时区
	atime, _ := time.ParseInLocation(timeLayout, datetime, loc)
	timestamp = atime.Unix()

	return
}

// timeNow := tNow.Format("2006-01-02 15:04:05")
func Str2Int64(in string) int64 {
	i64, _ := strconv.ParseInt(in, 10, 64)
	return i64
}
func Str2Float64(in string) float64 {
	f64, _ := strconv.ParseFloat(in, 64)
	return f64
}

func Bool2Str(b bool) string {
	if b {
		return "true"
	}
	return "false"
}
func BoolPtr2Str(b *bool) string {
	if b == nil {
		return ""
	}
	if *b {
		return "true"
	}
	return "false"
}

func Str2BoolPtr(s string) *bool {
	if s == "" {
		return nil
	}
	b := s == "true"
	return &b
}

func Int64ToLocalDateInt(sec int64) basemodel.LocalDateInt {

	return basemodel.LocalDateInt{time.Unix(sec, 0)}
}

func Int64ToLocalDateIntPtr(sec int64) *basemodel.LocalDateInt {

	return &basemodel.LocalDateInt{time.Unix(sec, 0)}
}

func Int64ToLocalTimeIntPtr(sec int64) *basemodel.LocalTimeInt {

	return &basemodel.LocalTimeInt{time.Unix(sec, 0)}
}

func Int64ToLocalTimeInt(sec int64) basemodel.LocalTimeInt {

	return basemodel.LocalTimeInt{time.Unix(sec, 0)}
}

func Int64ToLocalTimeIntUtcPtr(sec int64) *basemodel.LocalTimeUTCInt {

	return &basemodel.LocalTimeUTCInt{time.Unix(sec, 0).UTC()}
}

func Int64ToLocalTimeUtcInt(sec int64) basemodel.LocalTimeUTCInt {

	return basemodel.LocalTimeUTCInt{time.Unix(sec, 0).UTC()}
}

func CheckQueryParamUsing(param *interface{}) (ok bool) {
	switch v := (*param).(type) {
	case bool:
		fmt.Println(bool(v))
	case float32:
		fmt.Println(float32(v))

	default:
		fmt.Println(string(v.(string)))

	}
	return true
}

// LocalTimeInt
func Ip4() string {
	var ips []string
	addrs, err := net.InterfaceAddrs()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, address := range addrs {

		// 检查ip地址判断是否回环地址
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				ip := ipnet.IP.To4()
				for _, v := range ip {

					ips = append(ips, baseutils.ToStr(int(v)))
				}
				return strings.Join(ips, ".")
			}

		}
	}
	return ""
}
